﻿using System;
using System.Collections.Generic;
using System.Text;
using EnCor.ServiceLocator;
using EnCor.Config;
using System.Reflection;

namespace EnCor.ModuleLoader
{
    public class ServiceBuilder
    {
        private IServiceContainer _Container;
        internal ServiceBuilder(IServiceContainer container)
        {
            _Container = container;
        }

        public BizService BuildService(ServiceConfig config)
        {
            IServiceContainer childContainer = _Container.CreateChildContainer();
            ServiceComponentFactory componentFactory = new ServiceComponentFactory();
            foreach (ServiceComponentConfig componentConfig in config.ComponentsConfig)
            {
                object component = componentFactory.BuildComponent(componentConfig);
                childContainer.RegisterService(componentConfig.InterfaceType, component);

                //childContainer.RegisterPropertyInjection(config.Type, componentConfig.Name);
            }

            //foreach (PropertyInfo p in config.Type.GetProperties())
            //{
            //    if (p.CanWrite && Attribute.GetCustomAttribute(p, typeof(DependencyAttribute)) != null)
            //    {
            //        childContainer.RegisterPropertyInjection(config.Type, p.Name);
            //    }
            //}
            var constructors = config.Type.GetConstructors();
            if ( constructors.Length == 0 )
            {
                throw new EnCorException(string.Format("Service {0} has no public contructor, cannot complete build process", config.Type));
            }
            ConstructorInfo maximumConstractor = constructors[0];
            if (constructors.Length >= 1)
            {
                foreach (var constructor in constructors)
                {
                    if (constructor.GetParameters().Length > maximumConstractor.GetParameters().Length)
                    {
                        maximumConstractor = constructor;
                    }
                }
            }

            List<object> parameters = new List<object>();
            foreach (ParameterInfo p in maximumConstractor.GetParameters())
            {
                object dependent = childContainer.GetService(p.ParameterType);
                if (dependent == null)
                {
                    throw new EnCorException(string.Format("Cannot find dependent service {0} for service {1}", p.ParameterType, config.Type));
                }
                parameters.Add(dependent);
            }
            BizService serviceInstance = (BizService)maximumConstractor.Invoke(parameters.ToArray());
            

            //BizService serviceInstance = (BizService)Activator.CreateInstance(config.Type);
            
            //childContainer.BuildUp(serviceInstance.GetType(), serviceInstance);

            return serviceInstance;
        }
    }
}
